package com.menghao.sso.server.model.ticket;

import com.menghao.sso.server.model.validation.Authentication;
import com.menghao.sso.server.registry.ExpirationPolicy;
import com.menghao.sso.server.model.Service;
import lombok.Getter;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * TGT是系统中委托人的全局标识符，它授予主体单点登录访问任何单点登录的服务。
 */
public final class TicketGrantingTicketImpl extends AbstractTicket implements TicketGrantingTicket {

    private static final long serialVersionUID = -8673232562725683059L;

    /**
     * 为其生成此凭单的已验证对象
     */
    @Getter
    private final Authentication authentication;

    private boolean expired = false;

    public TicketGrantingTicketImpl(final String id,
                                    final TicketGrantingTicket ticketGrantingTicket,
                                    final Authentication authentication, final ExpirationPolicy policy) {
        super(id, ticketGrantingTicket, policy);

        if (authentication == null) {
            throw new IllegalArgumentException(
                    "authentication cannot be null on " + this.getClass().getName());
        }

        this.authentication = authentication;
    }

    public TicketGrantingTicketImpl(final String id, final Authentication authentication, final ExpirationPolicy policy) {
        this(id, null, authentication, policy);
    }

    public synchronized ServiceTicket grantServiceTicket(final String id, final Service service, final ExpirationPolicy expirationPolicy) {
        final ServiceTicket serviceTicket =
                new ServiceTicketImpl(id, this, service, this.getCountOfUses() == 0, expirationPolicy);
        this.incrementCountOfUses();
        return serviceTicket;
    }

    public boolean isRoot() {
        return this.getGrantingTicket() == null;
    }

    public void expire() {
        this.expired = true;
    }

    public boolean isExpiredInternal() {
        return this.expired || (this.getGrantingTicket() != null && this.getGrantingTicket().isExpired());
    }

    public List<Authentication> getChainedAuthentications() {
        final List<Authentication> list = new ArrayList<Authentication>();

        if (this.getGrantingTicket() == null) {
            list.add(this.getAuthentication());
            return Collections.unmodifiableList(list);
        }
        list.add(this.getAuthentication());
        list.addAll(this.getGrantingTicket().getChainedAuthentications());
        return Collections.unmodifiableList(list);
    }
}
